<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    // 1- call来自于Function.prototype
    // 2- call接收N个参数，第一个参数是绑定的this指向，从第二个参数开始即是传递的参数。
    // 3- call干了什么？
    //    3-1:调用函数fn
    //    3-2:指定函数fn中的this指向
    //    3-3:指定函数fn接收的参数
    // Function.prototype.call = function (a, ...arg) {
    //     // 调用
    //     // this();
    //
    //     // 指定函数fn中的this指向1
    //     // 通过隐式绑定指定fn中的this(将函数fn作为绑定包装对象的属性。)
    //     // // 生成包装对象：
    //     // const content = new Number(a);
    //     // // 将this作为content下的某个属性值。
    //     // content.suibian = this;
    //     // // 调用
    //     // content.suibian();
    //     // // 删除
    //     // delete content.suibian;
    //
    //     // 指定函数fn中的this指向2
    //     // 生成包装对象
    //     // const content = new Number(a);
    //     // Object.prototype.suibian = this;
    //     // console.log(content.__proto__ === Number.prototype);
    //     // console.log(Number.prototype.__proto__ === Object.prototype);
    //     // console.log(Object.prototype.__proto__);
    //     // content.suibian();
    //     // delete Object.prototype.suibian;
    //
    //
    //     // 判断是否为基本包装类型
    //     let content = a;//  content的值即是调用函数fn中的this指向。
    //     const aTypeOf = typeof a;
    //     if (aTypeOf === "string" || aTypeOf === "nubmer" || aTypeOf === "boolean") {
    //         content = new Object(a);
    //     }else if(a === undefined || a === null){
    //         content = window;
    //     }
    //     Object.prototype.suibian = this;
    //     content.suibian(...arg);
    //     delete Object.prototype.suibian;
    // }


    // 整理
    // Function.prototype.call = function (a, ...arg) {
    //     // 判断是否为基本包装类型
    //     let content = a;//  content的值即是调用函数fn中的this指向。
    //     const aTypeOf = typeof a;
    //     if (aTypeOf === "string" || aTypeOf === "nubmer" || aTypeOf === "boolean") {
    //         content = new Object(a);
    //     }else if(a === undefined || a === null){
    //         content = window;
    //     }
    //     Object.prototype.suibian = this;
    //     content.suibian(...arg);
    //     delete Object.prototype.suibian;
    // }

    // 优化
    Function.prototype.call = function (content, ...arg) {
        // 判断是否为基本包装类型
        const aTypeOf = typeof content;
        if (aTypeOf === "string" || aTypeOf === "nubmer" || aTypeOf === "boolean") {
            content = new Object(content);
        }else if(content === undefined || content === null){
            content = window;
        }
        const fnName = Math.random().toString(36).slice(2);
        Object.prototype[fnName] = this;
        const result = content[fnName](...arg);
        delete Object.prototype[fnName];
        return result;
    }

    function fn(a, b, c, d) {
        console.log("fn", this, a, b, c, d);// 2 3 4
    }

    fn.call(1, 2, 3, 4, 5);
    // console.log(fn.__proto__ === Function.prototype);
</script>
</html>